package com.qidian.k12.service.impl;

import com.qidian.k12.dto.PageInfo;
import com.qidian.k12.mapper.TemplateItemMapper;
import com.qidian.k12.pojo.Template;
import com.qidian.k12.mapper.TemplateMapper;
import com.qidian.k12.pojo.TemplateItem;
import com.qidian.k12.service.TemplateService;
import com.qidian.k12.util.JsonTools;
import com.qidian.k12.util.K12Result;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.io.IOException;
import java.io.InputStream;
import java.util.*;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.TimeUnit;

/**
 * (Template)表服务实现类
 *
 * @author makejava
 * @since 2021-10-28 09:02:10
 */
@Service("templateService")
public class TemplateServiceImpl implements TemplateService {
    @Resource
    private TemplateMapper templateMapper;
    @Resource
    private TemplateItemMapper itemMapper;
    @Resource
    private StringRedisTemplate redisTemplate;

    @Transactional
    public K12Result importTemplate(InputStream in,String fileName){
        // 准备一个集合用来存储所有的导入成功的模版
        List<Template> templates = new ArrayList<>();
        // 将集合设置到K12Result中
        K12Result result =K12Result.ok(templates);
        StringBuilder sb = new StringBuilder();

        // 准备解析文件
        // 创建workbook的时候传入文件流
        Workbook workbook =  null;
        try {
            if(fileName.endsWith("xlsx")){
                workbook = new XSSFWorkbook(in);
            }else{
                workbook = new HSSFWorkbook(in);
            }
            //开始解析：
            Iterator<Sheet> sheets = workbook.iterator();
            while(sheets.hasNext()){
                Map parseSheetResult = parseSheet(sheets.next());
                if(!new Boolean(parseSheetResult.get("result").toString())){
                    // 记录错误信息
                    sb.append(parseSheetResult.get("msg"));
                    result.setStatus(K12Result.ResultStatus.OK_PART);
                }else{
                    // 将返回的结果加入到templates集合中。
                    templates.add((Template) parseSheetResult.get("template"));
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
            throw new RuntimeException(e);
        }
        result.setMsg(sb.toString());
        return result;
    }
    // 解析一个sheet，成功返回true，否则返回false

    /**
     *
     * @param sheet
     * @return {result:true,msg:"",template: template}
     */
    private Map parseSheet(Sheet sheet){
        Map map = new HashMap();
        map.put("result",true);

//        map.put("template",template);
        // 取出模版
        // 按照格式解析：
        int lastRowNum = sheet.getLastRowNum();
        // 读取模版信息 (第二行)
        Row row = sheet.getRow(1);
        Template template = new Template();
        //模版名称
        try {
            String templateName = row.getCell(1).toString();
            System.out.println("模版名称："+templateName);
            if(templateName.equals("")){
                throw new RuntimeException("模版名称为空");
            }
            template.setTemplateName(templateName);
        } catch (Exception e) {
            e.printStackTrace();
            map.put("result",false);// 模版解析失败
            map.put("msg","模版解析失败,sheet的索引是:"+sheet.getSheetName());
            return map;
        }
        try {
            String templateDesc = row.getCell(2).toString();
            System.out.println("模版描述："+templateDesc);
            template.setTemplateDesc(templateDesc);
        } catch (Exception e) {
//            e.printStackTrace();
        }
        // 补全其他属性
        Date time = new Date();
        template.setCreateTime(time);
        template.setModifyTime(time);
        template.setTemplateStatus(1);
        //直接保存
        K12Result r  = insert(template);
        if(r.getStatus()==200){
            map.put("msg","<p>"+sheet.getSheetName()+"中的模版["+sheet.getSheetName()+"]保存成成功</p>");
            //模版已经保存成功,将template加入map
            map.put("template",template);
            // 解析模版项
            //解析模版项 从第四行遍历到最后
            List<TemplateItem> items = new ArrayList<>();
            for(int index = 4;index <= lastRowNum;index++){
                //逐行获取
                Row itemRow = sheet.getRow(index);
                TemplateItem item = new TemplateItem();
                item.setTemplateId(template.getTemplateId());
                // 逐列获取
                try {
                    String itemName = itemRow.getCell(1).toString();
                    item.setItemName(itemName);
                    float itemProportion = new Float(itemRow.getCell(2).toString());
                    item.setItemProportion((int)(itemProportion));
                    float itemMaxScore = new Float(itemRow.getCell(3).toString());
                    item.setItemMaxScore((int)(itemMaxScore));
                    System.out.println(itemName+":"+itemProportion+":"+itemMaxScore);
                    // 补全其他属性
                    item.setCreateTime(time);
                    item.setModifyTime(time);
                    item.setItemStatus(1);
                    // 保存item
                    items.add(item);
                } catch (NumberFormatException e) {
                    e.printStackTrace();
                }
            }
            //批量保存
            if(itemMapper.insertBatch(items)>0){
                // 将保存的items设置到template
                template.setTemplateItems(items);
            }
        }else if(r.getStatus()==505){
            map.put("result",false);// 模版解析失败
            map.put("msg","<p>"+sheet.getSheetName()+"中的模版["+template.getTemplateName()+"]名称重复<p/>");
            return map;
        }else{
            map.put("result",false);// 模版解析失败
            map.put("msg","模版解析失败,sheet的索引是:"+sheet.getSheetName());
            return map;
        };
        // 获取模版项
        return map;
    }

    @Override
    public K12Result queryByName(String templateName) {
        return K12Result.ok(templateMapper.queryByName(templateName));
    }

    public PageInfo<Template> queryByPage(Map map){
        PageInfo<Template> pageInfo = new PageInfo<>();
        int page = new Integer(map.get("page").toString());
        int rows = new Integer(map.get("row").toString());
        pageInfo.setPage(page);
        pageInfo.setRow(rows);
        // 查询总条数
        int total = templateMapper.total(map);
        pageInfo.setTotal(total);
        int maxPageNum = (int)(Math.ceil(total * 1.0 / rows));
        pageInfo.setMaxPageNun(maxPageNum);
        // 计算分页栏中的开始和结束位置
        //计算页码的开始位置和结束位置
        int pageStart = 1;
        int pageEnd = 10;
        if(page - 4 > 1){
            pageStart = page - 4;
        }
        if(page + 5 > maxPageNum){
            pageEnd = (int) maxPageNum;
        }
        pageInfo.setPageStart(pageStart);
        pageInfo.setPageEnd(pageEnd);
        //查询数据
        pageInfo.setData(templateMapper.queryByPage(map));
        return pageInfo;
    }

    /**
     * 通过ID查询单条数据
     *
     * @param templateId 主键
     * @return 实例对象
     */
    @Override
    public Template queryById(Long templateId) {
        // 这里的key在实际的工作中都是配置在配置文件中
        String key = "template_"+templateId;
        // 查询缓存
        if(redisTemplate.hasKey(key)) {
            String templateJson = redisTemplate.opsForValue().get(key);
            if(templateJson != null && !"".equals(templateJson)){
                try {
                    //转换
                    Template template = JsonTools.string2Obj(templateJson, Template.class);
                    // 查询到数据直接返回
                    return template;
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }
        // 如果上面没有返回（redis中没有缓存，或者缓存不正确）
        // 从数据库查询模版
        Template template = this.templateMapper.queryById(templateId);
        // 查询所有的模版项
        template.setTemplateItems(itemMapper.queryByTempId(templateId));
        // 将template转换为json存入redis
        String json = JsonTools.obj2String(template);
        redisTemplate.opsForValue().set(key,json);
        //设置存活时间
        // 设置时间为30分钟。 一般这里的时间都是必须错开的。
        redisTemplate.expire(key,30, TimeUnit.MINUTES);
        return template;
    }


    /**
     * 新增数据
     *
     * @param template 实例对象
     * @return 实例对象
     */
    @Override
    public K12Result insert(Template template) {
        K12Result result = K12Result.error();
        // 判断名称是否重复。
        if(template!=null && template.getTemplateName()!=null && !"".equals(template.getTemplateName())){
            List<Template> ts = templateMapper.searchByName(template.getTemplateName());
            if(ts!=null && ts.size()>0){
                return K12Result.dataExists();
            }
        }
        // 补全响应的数据。
        Date date = new Date();
        template.setCreateTime(date);
        template.setModifyTime(date);
        template.setTemplateStatus(1);
        int res = this.templateMapper.insert(template);
        if(res==1){//添加成功
            result = K12Result.ok();
            result.setData(template);
            return  result;
        }
        return result;
    }

    /**
     * 修改数据
     *
     * @param template 实例对象
     * @return 实例对象
     */
    @Override
    public K12Result update(Template template) {
        String key = "template_"+template.getTemplateId();
        // 先删缓存
        redisTemplate.delete(key);
        K12Result result = K12Result.error();
        template.setModifyTime(new Date());
        if(this.templateMapper.update(template)==1){
            result  = K12Result.ok();
            result.setData(this.queryById(template.getTemplateId()));
            // 修改完成，延迟 600毫秒，再次删除缓存
            // 开启一个线程，处理这个任务。  // 开启一个任务
            //  放在一个线程池中执行   注意：这个任务必须立刻执行，不能缓存。
            // 这里就涉及到线程池的相关问题: 1、任务不能缓存（SynchronousQueue）。  2、处理好拒绝策略(重复测试)。
            new Thread(()->{
                try {
                    Thread.sleep(600);
                    redisTemplate.delete(key);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }).start();
        };
        return result;
    }

    /**
     * 通过主键删除数据
     *
     * @param templateId 主键
     * @return 是否成功
     */
    @Override
    public boolean deleteById(Long templateId) {
        return this.templateMapper.deleteById(templateId) > 0;
    }
}
